import {
  DeputyGeneralListResponse,
  DeputyGeneralDetailInfo,
  CreateDeputyGeneralRequest,
  GenerateDeputyGeneralResponse,
} from "../interfaces/deputy-general.interface";
import {
  Injectable,
  Logger,
  BadRequestException,
  NotFoundException,
} from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository, In, MoreThan, QueryRunner, DataSource } from "typeorm";
import { DeputyGeneral } from "../entities/deputy-general.entity";
import { DeputyGeneralBase } from "../entities/deputy-general-base.entity";
import { PlayerDeputy } from "../entities/player-deputy.entity";
import { DeputyGeneralSkillLearned } from "../entities/deputy-general-skill-learned.entity";
import { SkillBase } from "../entities/skill-base.entity";
import { CharacterInventoryEntity } from "../entities/character-inventory.entity";
import { PlayerDeputyWarehouse } from "../entities/player-deputy-warehouse.entity";
import { RedisService } from "./redis.service";
import { LevelExperienceEntity } from "../entities/level-experience.entity";
import { DeputyAttributeService } from "./deputy-attribute.service";
import {
  TalentStoneEntity,
  TalentStoneBaseEntity,
} from "../entities/talent-stone.entity";

@Injectable()
export class DeputyGeneralService {
  private readonly logger = new Logger(DeputyGeneralService.name);

  constructor(
    @InjectRepository(DeputyGeneral)
    private deputyGeneralRepository: Repository<DeputyGeneral>,
    @InjectRepository(DeputyGeneralBase)
    private deputyGeneralBaseRepository: Repository<DeputyGeneralBase>,
    @InjectRepository(PlayerDeputy)
    private playerDeputyRepository: Repository<PlayerDeputy>,
    @InjectRepository(DeputyGeneralSkillLearned)
    private deputyGeneralSkillLearnedRepository: Repository<DeputyGeneralSkillLearned>,
    @InjectRepository(SkillBase)
    private skillBaseRepository: Repository<SkillBase>,
    @InjectRepository(CharacterInventoryEntity)
    private characterInventoryRepository: Repository<CharacterInventoryEntity>,
    @InjectRepository(PlayerDeputyWarehouse)
    private playerDeputyWarehouseRepository: Repository<PlayerDeputyWarehouse>,
    @InjectRepository(LevelExperienceEntity)
    private levelExperienceRepository: Repository<LevelExperienceEntity>,
    private readonly redisService: RedisService,
    private readonly dataSource: DataSource,
    private readonly deputyAttributeService: DeputyAttributeService
  ) {}

  /**
   * 计算副将抗性（仅叠加副将身上已装备的天赋石/魂蛋的抗性效果）
   * 约束：不计算装备随机抗性与其他来源；概率类（命中/暴击/反击/反震/躲闪/法爆/致命）统一为 0
   * 返回键名对齐前端 1109 期望：kwldj, kwk, kfjn, kfs, kd, kxhp, krl, kyh, kll 以及 dsl/fjl/fsbjl/fzl/mzl/wlbjl/zml
   */
  async calculateDeputyResistancesFromStones(
    characterId: number,
    deputyId: number
  ): Promise<{
    // 概率类
    mzl: number; // 命中率
    dsl: number; // 躲闪率
    wlbjl: number; // 物理暴击率
    fsbjl: number; // 法术暴击率
    fjl: number; // 反击率
    fzl: number; // 反震率
    zml: number; // 致命率
    // 抗性类（副将键名）
    kwldj: number; // 抗物理
    kwk: number; // 抗围困
    kfjn: number; // 抗封禁/封印
    kfs: number; // 抗风系/风沙
    kd: number; // 抗毒
    kxhp: number; // 抗玄
    krl: number; // 抗扰乱
    kyh: number; // 抗妖火
    kll: number; // 抗落雷
  }> {
    // 初始化为 0（仅计算宝石带来的抗性）
    const result = {
      // 概率类
      mzl: 0,
      dsl: 0,
      wlbjl: 0,
      fsbjl: 0,
      fjl: 0,
      fzl: 0,
      zml: 0,
      // 抗性类
      kwldj: 0,
      kwk: 0,
      kfjn: 0,
      kfs: 0,
      kd: 0,
      kxhp: 0,
      krl: 0,
      kyh: 0,
      kll: 0,
    };

    // 查询已装备到该副将的天赋石（state=3）
    const stoneRepo = this.dataSource.getRepository(TalentStoneEntity);
    const baseRepo = this.dataSource.getRepository(TalentStoneBaseEntity);
    const stones = await stoneRepo.find({
      where: { characterId, deputyId, state: 3 },
    });
    if (!stones || stones.length === 0) return result;

    // 批量读取基础配置以获取每种类型的基础效果值
    const typeIds = Array.from(new Set(stones.map((s) => Number(s.type))));
    const bases = await baseRepo.find({
      where: typeIds.length
        ? (typeIds as unknown as any[]).map((id) => ({ typeId: id }))
        : [],
    } as any);
    const typeToBaseEffect = new Map<number, number>();
    for (const b of bases) {
      typeToBaseEffect.set(
        Number((b as any).typeId),
        Number((b as any).baseEffect || 0)
      );
    }

    // 数字类型 -> 抗性键（k_*）
    const mapNumericTypeToK: Record<number, keyof typeof deputyKMap> = {
      33: "k_wl", // 抗物理
      34: "k_wei", // 抗围困
      35: "k_luan", // 抗扰乱
      36: "k_feng", // 抗封
      37: "k_fa", // 抗风
      38: "k_yao", // 抗妖
      39: "k_ll", // 抗雷
      40: "k_du", // 抗毒
    } as const;

    // k_* -> 副将字段名映射
    const deputyKMap: Record<string, keyof typeof result> = {
      k_wl: "kwldj",
      k_wei: "kwk",
      k_feng: "kfjn",
      k_fa: "kfs",
      k_du: "kd",
      k_xi: "kxhp",
      k_luan: "krl",
      k_yao: "kyh",
      k_ll: "kll",
    } as const;

    for (const s of stones) {
      const t = Number(s.type);
      const k = mapNumericTypeToK[t];
      if (!k) continue; // 仅处理抗性类类型
      const deputyKey = deputyKMap[k];
      if (!deputyKey) continue;
      // 取基础表效果值（若无则按 0 处理）
      const val = typeToBaseEffect.get(t) ?? 0;
      result[deputyKey] += Math.max(0, Math.floor(val));
    }

    return result;
  }

  private getLevelCap(transCount: number): number {
    if (!transCount || transCount <= 0) return 100;
    if (transCount === 1) return 120;
    if (transCount === 2) return 140;
    return 160;
  }

  /**
   * 在同一事务中扣除银两
   */
  private async paySilverInTx(
    queryRunner: QueryRunner,
    characterId: number,
    amount: number
  ): Promise<void> {
    if (amount <= 0) return;
    const res = await queryRunner.manager.findOne(
      (
        await import("../entities/character-resources.entity")
      ).CharacterResourcesEntity,
      { where: { characterId } }
    );
    if (!res || Number(res.silver) < amount) {
      throw new BadRequestException(
        "您的银两不足,无法完成操作.",
        "SILVER_NOT_ENOUGH"
      );
    }
    await queryRunner.manager.update(
      (
        await import("../entities/character-resources.entity")
      ).CharacterResourcesEntity,
      { characterId },
      { silver: Number(res.silver) - amount, updated_at: new Date() as any }
    );
  }

  /**
   * 1396 action=2 副将技能重修：扣2万银、清空技能、学习新技能、职业随技能类型变更
   */
  async relearnDeputySkill(
    playerId: number,
    deputyId: number,
    skillId?: number
  ): Promise<{
    deputy_id: number;
    skill_id: number;
    skill_name: string;
    role_type: number;
    msg: string;
  }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      // 所属校验
      const pd = await queryRunner.manager.findOne(PlayerDeputy, {
        where: { deputy_id: deputyId, player_id: playerId },
      });
      if (!pd) throw new BadRequestException("副将不属于当前玩家", "1002");

      const deputy = await queryRunner.manager.findOne(DeputyGeneral, {
        where: { id: deputyId },
        relations: ["base"],
      } as any);
      if (!deputy) throw new NotFoundException("副将不存在", "1001");

      // 扣费：2万银
      await this.paySilverInTx(queryRunner, playerId, 20000);

      // 选择新技能：若传了 skillId 则校验并使用；否则随机一个常规技能(type 1-3)
      let targetSkill: SkillBase | null = null;
      if (skillId && Number(skillId) > 0) {
        targetSkill = await queryRunner.manager.findOne(SkillBase, {
          where: { id: Number(skillId) },
        });
        if (!targetSkill) {
          throw new BadRequestException("技能不存在", "1018");
        }
      } else {
        const qb = queryRunner.manager
          .getRepository(SkillBase)
          .createQueryBuilder("s")
          .where("s.type IN (:...types)", { types: [1, 2, 3] })
          .orderBy("RAND()")
          .limit(1);
        targetSkill = (await qb.getOne()) as SkillBase | null;
        if (!targetSkill) {
          throw new BadRequestException("暂无可用技能", "1018");
        }
      }

      // 清空已学技能
      await queryRunner.manager.delete(DeputyGeneralSkillLearned, {
        deputy_id: deputyId,
      });

      // 新增技能，等级1，熟练度0
      const learned = queryRunner.manager.create(DeputyGeneralSkillLearned, {
        deputy_id: deputyId,
        skill_id: targetSkill.id,
        grade: 1,
        order: 1,
        use_count: 0,
        hua: 0,
        created_at: new Date() as any,
        updated_at: new Date() as any,
      });
      await queryRunner.manager.save(DeputyGeneralSkillLearned, learned);

      // 职业随技能类型变更
      await queryRunner.manager.update(DeputyGeneral, deputyId, {
        roleType: targetSkill.type,
        updated_at: new Date() as any,
      });

      await queryRunner.commitTransaction();

      const name = deputy.base?.name || "副将";
      const roleMap: Record<number, string> = {
        1: "武士",
        2: "文人",
        3: "异师",
      };
      const roleName = roleMap[targetSkill.type] || "未知";
      const msg = `您的副将${name}成功重新学到了[${targetSkill.name}],他现在的职业是${roleName},以后在战斗中使用会增加熟练度!`;
      return {
        deputy_id: deputyId,
        skill_id: targetSkill.id,
        skill_name: targetSkill.name,
        role_type: targetSkill.type,
        msg,
      };
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw e;
    } finally {
      await queryRunner.release();
    }
  }

  private async applyDeputyExperience(
    queryRunner: QueryRunner,
    deputy: DeputyGeneral,
    expGained: number
  ): Promise<{ newLevel: number; newExp: number; levelUpTimes: number }> {
    let level = deputy.lvl;
    let expRemaining = Number(deputy.exp) - Math.max(0, expGained);
    let levelUpTimes = 0;
    const levelCap = this.getLevelCap(deputy.trans_count || 0);

    while (expRemaining <= 0 && level < levelCap) {
      levelUpTimes += 1;
      level += 1;
      const overflow = -expRemaining;
      const levelRow = await queryRunner.manager.findOne(
        LevelExperienceEntity,
        {
          where: { level },
        }
      );
      const nextNeed = levelRow?.experience
        ? Number(levelRow.experience)
        : level * 1000;
      expRemaining = nextNeed - overflow;
      // 升级触发：四维各+1，未分配+4（通过点数服务维护总量，与主将一致）
      try {
        await this.deputyAttributeService.onLevelUp(deputy.id, level);
      } catch {}
    }

    if (level >= levelCap && expRemaining < 0) {
      expRemaining = 0;
    }

    deputy.lvl = level;
    deputy.exp = expRemaining as any;
    deputy.updated_at = new Date() as any;

    // 升级后：回满副将当前血量/蓝量到计算后的最大值
    try {
      // 计算最新最大属性
      const calc = await this.deputyAttributeService.calculate(deputy.id);
      const fullHp = Math.max(1, Number((calc as any).hp || deputy.hp));
      const fullMp = Math.max(1, Number((calc as any).mp || deputy.mp));
      deputy.hp = fullHp;
      deputy.mp = fullMp;
    } catch {}

    await queryRunner.manager.save(DeputyGeneral, deputy);

    return { newLevel: level, newExp: expRemaining, levelUpTimes };
  }

  private async consumeInventoryItem(
    queryRunner: QueryRunner,
    characterId: number,
    itemId: number,
    count: number
  ): Promise<void> {
    const inv = await queryRunner.manager.findOne(CharacterInventoryEntity, {
      where: { characterId, itemId },
    });
    if (!inv || (inv.num || 0) < count) {
      throw new BadRequestException("您没有这个物品", "NO_ITEM");
    }
    const newNum = (inv.num || 0) - count;
    await queryRunner.manager.update(
      CharacterInventoryEntity,
      { id: inv.id },
      newNum > 0
        ? { num: newNum, updated_at: new Date() }
        : { num: 0, status: 0, updated_at: new Date() }
    );
  }

  async getDeputyMindEligibleList(
    characterId: number,
    itemGid: number,
    pageNum: number = 0
  ): Promise<{ list: Array<{ id: number; name: string }>; sum: number }> {
    // 校验物品是否存在
    const inv = await this.characterInventoryRepository.findOne({
      where: { characterId, itemId: itemGid },
    });
    if (!inv || (inv.num || 0) <= 0) {
      throw new BadRequestException("您没有这个物品", "NO_ITEM");
    }

    // 解析物品类型（用于过滤范围）
    let useLevelMin: number | null = null;
    let useLevelMax: number | null = null;
    let restrictStars: number[] | null = null; // 常人心法：仅常人(1)/将才(3)

    // 尝试读取物品名称，识别常人心法
    let itemName: string | null = null;
    try {
      const itemRow = await this.playerDeputyRepository.manager.query(
        "SELECT name FROM basic_items WHERE id = ? LIMIT 1",
        [itemGid]
      );
      itemName = itemRow?.[0]?.name || null;
    } catch {}

    // 2030类心法（按等级段）
    if (itemGid === 147) {
      useLevelMin = 11;
      useLevelMax = 40;
    } else if (itemGid === 148) {
      useLevelMin = 41;
      useLevelMax = 70;
    } else if (itemGid === 149) {
      useLevelMin = 71;
      useLevelMax = 100;
    } else if (itemGid === 425) {
      useLevelMin = 101;
      useLevelMax = 120;
    } else if (itemName && /常人心法/.test(itemName)) {
      // 常人心法（4439）：限制品质，仅常人/将才；无等级段限制
      restrictStars = [1, 3];
    }

    // 列出玩家副将（最多10个，无分页或简单分页）
    const qb = this.playerDeputyRepository
      .createQueryBuilder("pd")
      .leftJoinAndSelect("pd.deputy", "deputy")
      .leftJoinAndSelect("deputy.base", "base")
      .where("pd.player_id = :pid", { pid: characterId })
      .orderBy("pd.id", "ASC");

    if (useLevelMin !== null && useLevelMax !== null) {
      qb.andWhere("deputy.lvl BETWEEN :min AND :max", {
        min: useLevelMin,
        max: useLevelMax,
      });
    }

    if (restrictStars && restrictStars.length > 0) {
      qb.andWhere("base.star_level IN (:...stars)", { stars: restrictStars });
    }

    const list = await qb.getMany();

    const mapped = list.map((pd) => ({
      id: pd.id,
      name: `${pd.deputy?.lvl || 1} 级${pd.deputy?.base?.name || "副将"}`,
    }));
    return { list: mapped, sum: mapped.length };
  }

  async useDeputyExpBook(
    characterId: number,
    itemGid: number,
    playerDeputyId: number
  ): Promise<{ expGained: number; levelUpTimes: number }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const pd = await queryRunner.manager.findOne(PlayerDeputy, {
        where: { id: playerDeputyId, player_id: characterId },
      });
      if (!pd) throw new BadRequestException("副将不属于当前玩家", "NO_OWNER");
      const deputy = await queryRunner.manager.findOne(DeputyGeneral, {
        where: { id: pd.deputy_id },
      });
      if (!deputy) throw new NotFoundException("副将不存在", "NOT_FOUND");

      const levelCap = this.getLevelCap(deputy.trans_count || 0);
      if (deputy.lvl >= levelCap) {
        throw new BadRequestException("已达等级上限，无法使用", "LEVEL_CAPPED");
      }

      // 消耗一本经验书
      await this.consumeInventoryItem(queryRunner, characterId, itemGid, 1);

      const expGained = 5000;
      const beforeLevel = deputy.lvl;
      const apply = await this.applyDeputyExperience(
        queryRunner,
        deputy,
        expGained
      );

      await queryRunner.commitTransaction();
      return { expGained, levelUpTimes: apply.newLevel - beforeLevel };
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw e;
    } finally {
      await queryRunner.release();
    }
  }

  async useDeputyMind(
    characterId: number,
    itemGid: number,
    playerDeputyId: number,
    count: number
  ): Promise<{
    expGained: number;
    levelUpTimes: number;
    fightsPerBook: number;
  }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const pd = await queryRunner.manager.findOne(PlayerDeputy, {
        where: { id: playerDeputyId, player_id: characterId },
      });
      if (!pd) throw new BadRequestException("副将不属于当前玩家", "NO_OWNER");
      const deputy = await queryRunner.manager.findOne(DeputyGeneral, {
        where: { id: pd.deputy_id },
      });
      if (!deputy) throw new NotFoundException("副将不存在", "NOT_FOUND");

      const levelCap = this.getLevelCap(deputy.trans_count || 0);
      if (deputy.lvl >= levelCap) {
        throw new BadRequestException("已达等级上限，无法使用", "LEVEL_CAPPED");
      }

      const c = Math.max(1, Math.min(100, Number(count) || 1));
      await this.consumeInventoryItem(queryRunner, characterId, itemGid, c);

      // 根据副将当前等级确定每本心法可折算的"标准战斗次数"
      const lvl = deputy.lvl;
      let fightsPerBook = 100;
      if (lvl >= 11 && lvl <= 40) fightsPerBook = 100;
      else if (lvl >= 41 && lvl <= 70) fightsPerBook = 150;
      else if (lvl >= 71 && lvl <= 100) fightsPerBook = 200;
      else if (lvl >= 101) fightsPerBook = 300;

      // 查询当前等级的每次标准战斗经验
      const levelRow = await queryRunner.manager.findOne(
        LevelExperienceEntity,
        { where: { level: lvl } }
      );
      const perFight =
        levelRow && (levelRow as any).standard_exp_per_fight
          ? Number((levelRow as any).standard_exp_per_fight)
          : 0;
      if (perFight <= 0) {
        throw new BadRequestException(
          "标准经验缺失，请先初始化 standard_exp_per_fight",
          "NO_STANDARD_EXP"
        );
      }
      const totalExp = perFight * fightsPerBook * c;

      // 立即结算
      const beforeLevel = deputy.lvl;
      const apply = await this.applyDeputyExperience(
        queryRunner,
        deputy,
        totalExp
      );

      await queryRunner.commitTransaction();
      return {
        expGained: totalExp,
        levelUpTimes: apply.newLevel - beforeLevel,
        fightsPerBook,
      };
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw e;
    } finally {
      await queryRunner.release();
    }
  }

  async useCommonMind(
    characterId: number,
    itemGid: number,
    playerDeputyId: number,
    count: number
  ): Promise<{
    expGained: number;
    levelUpTimes: number;
    fightsPerBook: number;
    grade: number;
  }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const pd = await queryRunner.manager.findOne(PlayerDeputy, {
        where: { id: playerDeputyId, player_id: characterId },
      });
      if (!pd) throw new BadRequestException("副将不属于当前玩家", "NO_OWNER");
      const deputy = await queryRunner.manager.findOne(DeputyGeneral, {
        where: { id: pd.deputy_id },
        relations: ["base"],
      } as any);
      if (!deputy) throw new NotFoundException("副将不存在", "NOT_FOUND");

      const levelCap = this.getLevelCap(deputy.trans_count || 0);
      if (deputy.lvl >= levelCap) {
        throw new BadRequestException("已达等级上限，无法使用", "LEVEL_CAPPED");
      }

      const c = Math.max(1, Math.min(100, Number(count) || 1));
      await this.consumeInventoryItem(queryRunner, characterId, itemGid, c);

      // 从 basic_items 解析心法等级（名称中包含 "级常人心法"）
      const itemRow = await queryRunner.manager.query(
        "SELECT name FROM basic_items WHERE id = ? LIMIT 1",
        [itemGid]
      );
      const itemName: string = itemRow?.[0]?.name || "";
      const gradeMatch = itemName.match(/(\d+)\s*级.*常人心法/);
      const grade = gradeMatch
        ? Math.max(1, Math.min(5, parseInt(gradeMatch[1], 10)))
        : 3; // 默认3级

      // 根据品质映射每本可折算的"标准战斗次数"
      // 英才=2, 将才=3, 常人=1（推测）
      const star = (deputy as any).base?.star_level || 1;
      const fightsByStar: Record<number, number[]> = {
        1: [100, 150, 200, 250, 300], // 常人
        3: [30, 45, 60, 75, 90], // 将才
      };
      const table = fightsByStar[star];
      if (!table) {
        throw new BadRequestException(
          "该品质副将无法使用常人心法",
          "NOT_APPLICABLE"
        );
      }
      const fightsPerBook = table[grade - 1];

      const lvl = deputy.lvl;
      const levelRow = await queryRunner.manager.findOne(
        LevelExperienceEntity,
        { where: { level: lvl } }
      );
      const perFight =
        levelRow && (levelRow as any).standard_exp_per_fight
          ? Number((levelRow as any).standard_exp_per_fight)
          : 0;
      if (perFight <= 0) {
        throw new BadRequestException(
          "标准经验缺失，请先初始化 standard_exp_per_fight",
          "NO_STANDARD_EXP"
        );
      }

      const totalExp = perFight * fightsPerBook * c;
      const beforeLevel = deputy.lvl;
      const apply = await this.applyDeputyExperience(
        queryRunner,
        deputy,
        totalExp
      );

      await queryRunner.commitTransaction();
      return {
        expGained: totalExp,
        levelUpTimes: apply.newLevel - beforeLevel,
        fightsPerBook,
        grade,
      };
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw e;
    } finally {
      await queryRunner.release();
    }
  }

  async claimDeputyMindPendingExp(
    characterId: number,
    playerDeputyId: number
  ): Promise<{
    appliedExp: number;
    levelUpTimes: number;
    newLevel: number;
    newExp: number;
  }> {
    const key = `deputy:pendingMindExp:${characterId}:${playerDeputyId}`;
    const raw = await this.redisService.get(key);
    const pending = parseInt(raw || "0", 10) || 0;
    if (pending <= 0) {
      throw new BadRequestException("没有可领取的经验", "NO_PENDING");
    }

    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const pd = await queryRunner.manager.findOne(PlayerDeputy, {
        where: { id: playerDeputyId, player_id: characterId },
      });
      if (!pd) throw new BadRequestException("副将不属于当前玩家", "NO_OWNER");
      const deputy = await queryRunner.manager.findOne(DeputyGeneral, {
        where: { id: pd.deputy_id },
      });
      if (!deputy) throw new NotFoundException("副将不存在", "NOT_FOUND");

      const beforeLevel = deputy.lvl;
      const apply = await this.applyDeputyExperience(
        queryRunner,
        deputy,
        pending
      );

      await queryRunner.commitTransaction();
      await this.redisService.set(key, "0", 7 * 24 * 3600);

      return {
        appliedExp: pending,
        levelUpTimes: apply.newLevel - beforeLevel,
        newLevel: apply.newLevel,
        newExp: apply.newExp,
      };
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw e;
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * 获取副将详细信息
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 副将详细信息，对齐标准数据格式
   */
  async getDeputyDetail(
    deputyId: number,
    playerId: number
  ): Promise<DeputyGeneralDetailInfo> {
    const deputy = await this.deputyGeneralRepository.findOne({
      where: { id: deputyId },
      relations: ["base"],
    });

    if (!deputy) {
      throw new NotFoundException("副将不存在", "1001");
    }

    const playerDeputy = await this.playerDeputyRepository.findOne({
      where: { deputy_id: deputyId, player_id: playerId },
    });

    if (!playerDeputy) {
      throw new BadRequestException("副将不属于当前玩家", "1002");
    }

    // 查询副将技能列表
    const skillList = await this.deputyGeneralSkillLearnedRepository
      .createQueryBuilder("skill")
      .leftJoinAndSelect("skill.skill", "skillBase")
      .where("skill.deputy_id = :deputyId", { deputyId })
      .getMany();

    // 查询副将装备列表
    const armingList = await this.deputyGeneralRepository.manager
      .createQueryBuilder()
      .select("*")
      .from("deputy_general_equipment", "equipment")
      .where("equipment.deputy_id = :deputyId", { deputyId })
      .getRawMany();

    // 查询副将宝石列表
    const stoneList = await this.deputyGeneralRepository.manager
      .createQueryBuilder()
      .select("*")
      .from("deputy_general_stone", "stone")
      .where("stone.deputy_id = :deputyId", { deputyId })
      .getRawMany();

    // 计算属性（与主将规则一致）
    let calc: any = {};
    try {
      calc = await this.deputyAttributeService.calculate(deputy.id);
    } catch {}

    // 标准称号映射：1=国士, 2=将才, 3=英才, 4=常人（默认常人）
    const starLevel = (deputy as any).base?.star_level || 4;
    const titleMap: Record<number, string> = {
      1: "国士",
      2: "将才",
      3: "英才",
      4: "常人",
    };
    const title = titleMap[starLevel] || "常人";

    // 返回标准格式的数据
    return {
      // 基础信息
      id: deputy.id,
      name: deputy.base?.name || "未知副将",
      img: deputy.base?.head_img || "default",
      roleType: deputy.roleType,
      star: deputy.star,
      lvl: deputy.lvl,
      exp: parseInt(deputy.exp.toString()),

      // 属性信息
      ap: calc.ap ?? deputy.ap,
      // 当前值使用表中当前血/精；最大值用计算结果，同时限制下限为0
      hp: Math.max(
        0,
        Math.min(
          deputy.hp,
          calc && typeof calc.hp === "number" ? calc.hp : deputy.hp
        )
      ),
      mp: Math.max(
        0,
        Math.min(
          deputy.mp,
          calc && typeof calc.mp === "number" ? calc.mp : deputy.mp
        )
      ),
      sp: calc.sp ?? deputy.sp,
      czl: parseFloat(deputy.czl.toString()),

      // 加点信息 (使用标准默认值)
      app: calc.app ?? deputy.ap_points,
      hpp: calc.hpp ?? deputy.hp_points,
      mpp: calc.mpp ?? deputy.mp_points,
      spp: calc.spp ?? deputy.sp_points,

      // 防御和状态 (使用标准默认值)
      df: 80, // TODO: 实现防御力计算
      status: 0, // TODO: 实现状态管理
      lock: false, // TODO: 实现锁定功能
      sack: true, // TODO: 实现背包状态

      // 位置和部署
      pos: playerDeputy.pos,
      p: calc && typeof calc.p === "number" ? calc.p : 0,

      // 培养相关
      trans: deputy.trans_count,
      mqd: deputy.compatibility,
      zcd: deputy.loyalty,
      up: 1, // TODO: 实现升级状态

      // 技能和装备
      skillList: skillList.map((skill) => ({
        id: skill.skill_id,
        name: skill.skill?.name || "未知技能",
        grade: skill.grade,
        useCount: skill.use_count || 0,
        order: skill.order || 1,
        hua: 0, // TODO: 实现技能花数
      })),
      armingList: armingList, // TODO: 完善装备列表格式
      stoneList: stoneList, // TODO: 完善宝石列表格式

      // 最大属性（根据属性服务计算结果）
      maxHp: calc && typeof calc.hp === "number" ? calc.hp : deputy.hp,
      maxMp: calc && typeof calc.mp === "number" ? calc.mp : deputy.mp,
      maxArming: 0, // TODO: 实现最大装备数
      maxStone: 1, // TODO: 实现最大宝石数

      // 特殊技能 (使用标准默认值)
      godSkill: false, // TODO: 实现神技判断

      // 称号（根据基础表星级映射）
      title,

      // 内部字段（保留用于后端处理）
      base_id: deputy.base_id,
      sp_points: deputy.sp_points,
      ap_points: deputy.ap_points,
      hp_points: deputy.hp_points,
      mp_points: deputy.mp_points,
      loyalty: deputy.loyalty,
      compatibility: deputy.compatibility,
      is_real: deputy.is_real,
      trans_count: deputy.trans_count,
      ultimate_skill_1_id: deputy.ultimate_skill_1_id,
      ultimate_skill_1_level: deputy.ultimate_skill_1_level,
      ultimate_skill_2_id: deputy.ultimate_skill_2_id,
      ultimate_skill_2_level: deputy.ultimate_skill_2_level,
      created_at: deputy.created_at,
      updated_at: deputy.updated_at,
      base: deputy.base,
      is_deployed: playerDeputy.pos > 0,
    };
  }

  /**
   * 获取玩家副将列表（最多10个，无需分页）
   * @param playerId 玩家ID
   * @param deployedOnly 是否只获取已上阵的副将，默认false
   * @returns 副将列表
   */
  async getDeputyList(
    playerId: number,
    deployedOnly: boolean = false
  ): Promise<DeputyGeneralListResponse> {
    const whereCondition: any = { player_id: playerId };

    // 如果只需要上阵的副将，添加pos > 0条件
    if (deployedOnly) {
      whereCondition.pos = MoreThan(0);
    }

    // 使用 QueryBuilder 实现自定义排序：1, 2, 3, 0, 0, 0...
    const queryBuilder = this.playerDeputyRepository
      .createQueryBuilder("playerDeputy")
      .leftJoinAndSelect("playerDeputy.deputy", "deputy")
      .leftJoinAndSelect("deputy.base", "base")
      .where("playerDeputy.player_id = :playerId", { playerId });

    // 如果只需要上阵的副将，添加pos > 0条件
    if (deployedOnly) {
      queryBuilder.andWhere("playerDeputy.pos > 0");
    }

    // 自定义排序：先按 1, 2, 3 的顺序，然后是 0 值
    queryBuilder
      .addSelect(
        "CASE " +
          "WHEN playerDeputy.pos = 1 THEN 1 " +
          "WHEN playerDeputy.pos = 2 THEN 2 " +
          "WHEN playerDeputy.pos = 3 THEN 3 " +
          "WHEN playerDeputy.pos = 0 THEN 4 " +
          "ELSE 5 " +
          "END",
        "sortOrder"
      )
      .addOrderBy("sortOrder", "ASC")
      .addOrderBy("playerDeputy.pos", "ASC")
      .limit(10);

    const playerDeputies = await queryBuilder.getMany();

    const deputies = playerDeputies.map((pd) => ({
      id: pd.deputy.id, // 副将ID
      lvl: pd.deputy.lvl, // 等级
      name: pd.deputy.base?.name || "未知副将", // 副将名称（从基础表获取）
      pos: pd.pos, // 上阵位置（来自PlayerDeputy表）
      roleType: pd.deputy.roleType, // 职业类型
      s: pd.deputy.base?.star_level || 0, // 星级（从基础表获取）
      star: pd.deputy.star, // 星级
      sex: pd.deputy.base?.sex || 0, // 性别（来自基础表）
      head_img: pd.deputy.base?.head_img || undefined, // 头像图片
    }));

    return {
      list: deputies, // 返回list字段以保持与前端兼容
      count: deputies.length, // 副将数量
    };
  }

  /**
   * 查询副将属性信息 (1110)
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 副将属性信息，包括基础表的最大最小值、副将表当前值、将军令数量
   */
  async getDeputyAttributes(deputyId: number, playerId: number): Promise<any> {
    // 查询副将信息，包括基础表数据
    const deputy = await this.deputyGeneralRepository
      .createQueryBuilder("deputy")
      .leftJoinAndSelect("deputy.base", "base")
      .leftJoin(
        "player_deputy",
        "pd",
        "pd.deputy_id = deputy.id AND pd.player_id = :playerId",
        { playerId }
      )
      .where("deputy.id = :deputyId", { deputyId })
      .getOne();

    if (!deputy) {
      throw new BadRequestException("副将不存在", "1001");
    }

    // 查询玩家拥有的将军令数量
    const jjlcCount = await this.characterInventoryRepository
      .createQueryBuilder("inventory")
      .leftJoin("basic_items", "item", "item.id = inventory.itemId")
      .where("inventory.characterId = :playerId", { playerId })
      .andWhere("item.name LIKE :jjlcName", { jjlcName: "将军令%" })
      .andWhere("inventory.status = 1")
      .select("SUM(inventory.num)", "total")
      .getRawOne();

    return {
      // 副将表当前属性值
      ap: deputy.ap,
      hp: deputy.hp,
      mp: deputy.mp,
      sp: deputy.sp,
      czl: parseFloat(deputy.czl.toString()),
      // 基础表最大最小值
      apMax: deputy.base.ap_max,
      apMin: deputy.base.ap_min,
      hpMax: deputy.base.hp_max,
      hpMin: deputy.base.hp_min,
      mpMax: deputy.base.mp_max,
      mpMin: deputy.base.mp_min,
      spMax: deputy.base.sp_max,
      spMin: deputy.base.sp_min,
      czlMax: parseFloat(deputy.base.czl_max.toString()),
      czlMin: parseFloat(deputy.base.czl_min.toString()),
      // 将军令数量
      jjlc: parseInt(jjlcCount?.total || "0"),
    };
  }

  /**
   * 洗副将属性 (1122)
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @param py 属性类型 (1-成长，2-气血，3-精力，4-攻击，5-速度)
   * @returns 洗属性结果，包含新属性值和消耗的将军令数量
   */
  async washDeputyAttribute(
    deputyId: number,
    playerId: number,
    py: number
  ): Promise<any> {
    // 验证属性类型参数
    if (![1, 2, 3, 4, 5].includes(py)) {
      throw new BadRequestException("无效的属性类型参数", "1018");
    }

    // 查询副将信息，包括基础表数据
    const deputy = await this.deputyGeneralRepository
      .createQueryBuilder("deputy")
      .leftJoinAndSelect("deputy.base", "base")
      .leftJoin(
        "player_deputy",
        "pd",
        "pd.deputy_id = deputy.id AND pd.player_id = :playerId",
        { playerId }
      )
      .where("deputy.id = :deputyId", { deputyId })
      .getOne();

    if (!deputy) {
      throw new BadRequestException("副将不存在", "1001");
    }

    // 查询玩家拥有的将军令数量
    const jjlcCount = await this.characterInventoryRepository
      .createQueryBuilder("inventory")
      .leftJoin("basic_items", "item", "item.id = inventory.itemId")
      .where("inventory.characterId = :playerId", { playerId })
      .andWhere("item.name LIKE :jjlcName", { jjlcName: "将军令%" })
      .andWhere("inventory.status = 1")
      .select("SUM(inventory.num)", "total")
      .getRawOne();

    const availableJjlc = parseInt(jjlcCount?.total || "0");
    if (availableJjlc < 1) {
      throw new BadRequestException("你没有将军令", "1008");
    }

    // 使用事务进行洗属性操作
    return await this.deputyGeneralRepository.manager.transaction(
      async (transactionalEntityManager) => {
        // 根据属性类型确定要洗的属性
        let attributeField: string;
        let minValue: number;
        let maxValue: number;
        let newValue: number;

        switch (py) {
          case 1: // 成长
            attributeField = "czl";
            minValue = parseFloat(deputy.base.czl_min.toString());
            maxValue = parseFloat(deputy.base.czl_max.toString());
            // 成长率是小数，保留2位小数
            newValue =
              Math.round(
                (Math.random() * (maxValue - minValue) + minValue) * 100
              ) / 100;
            break;
          case 2: // 气血
            attributeField = "hp";
            minValue = parseInt(deputy.base.hp_min.toString());
            maxValue = parseInt(deputy.base.hp_max.toString());
            newValue =
              Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
            break;
          case 3: // 精力
            attributeField = "mp";
            minValue = parseInt(deputy.base.mp_min.toString());
            maxValue = parseInt(deputy.base.mp_max.toString());
            newValue =
              Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
            break;
          case 4: // 攻击
            attributeField = "ap";
            minValue = parseInt(deputy.base.ap_min.toString());
            maxValue = parseInt(deputy.base.ap_max.toString());
            newValue =
              Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
            break;
          case 5: // 速度
            attributeField = "sp";
            minValue = parseInt(deputy.base.sp_min.toString());
            maxValue = parseInt(deputy.base.sp_max.toString());
            newValue =
              Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
            break;
          default:
            throw new BadRequestException("无效的属性类型", "1018");
        }

        // 更新副将属性
        const updateData: any = {};
        updateData[attributeField] = newValue;

        await transactionalEntityManager.update(
          DeputyGeneral,
          deputyId,
          updateData
        );

        // 扣减将军令数量
        const jjlcItem = await transactionalEntityManager
          .createQueryBuilder(CharacterInventoryEntity, "inventory")
          .leftJoin("basic_items", "item", "item.id = inventory.itemId")
          .where("inventory.characterId = :playerId", { playerId })
          .andWhere("item.name LIKE :jjlcName", { jjlcName: "将军令%" })
          .andWhere("inventory.status = 1")
          .andWhere("inventory.num > 0")
          .orderBy("inventory.id", "ASC")
          .getOne();

        if (!jjlcItem) {
          throw new BadRequestException("将军令物品不存在", "1009");
        }

        if (jjlcItem.num <= 0) {
          throw new BadRequestException("将军令数量不足", "1010");
        }

        // 扣减一个将军令
        await transactionalEntityManager.update(
          CharacterInventoryEntity,
          jjlcItem.id,
          {
            num: jjlcItem.num - 1,
          }
        );

        // 如果数量为0，标记为已使用
        if (jjlcItem.num - 1 === 0) {
          await transactionalEntityManager.update(
            CharacterInventoryEntity,
            jjlcItem.id,
            {
              status: 0,
            }
          );
        }

        // 获取原值并确保正确的数据类型
        const oldValue = (deputy as any)[attributeField];
        const formattedOldValue =
          attributeField === "czl"
            ? parseFloat(oldValue.toString())
            : parseInt(oldValue.toString());

        return {
          deputy_id: deputyId,
          attribute_type: py,
          attribute_field: attributeField,
          old_value: formattedOldValue,
          new_value: newValue,
          min_value: minValue,
          max_value: maxValue,
          jjlc_consumed: 1,
          remaining_jjlc: availableJjlc - 1,
        };
      }
    );
  }

  /**
   * 副将使用技能
   * @param deputyId 副将ID
   * @param skillId 技能ID
   * @param targetId 目标ID
   * @param playerId 玩家ID
   * @returns 技能使用结果，包含消耗的魔法值和剩余魔法值
   */
  async useSkill(
    deputyId: number,
    skillId: number,
    targetId: number,
    playerId: number
  ) {
    const deputy = await this.getDeputyDetail(deputyId, playerId);

    const learnedSkill = await this.deputyGeneralSkillLearnedRepository.findOne(
      {
        where: { deputy_id: deputyId, skill_id: skillId },
      }
    );

    if (!learnedSkill) {
      throw new BadRequestException("技能未学习", "1016");
    }

    if (deputy.mp < 10) {
      throw new BadRequestException("魔法值不足", "1015");
    }

    await this.deputyGeneralRepository.update(deputyId, { mp: deputy.mp - 10 });
    await this.deputyGeneralSkillLearnedRepository.update(
      { deputy_id: deputyId, skill_id: skillId },
      { use_count: learnedSkill.use_count + 1 }
    );

    return {
      deputy_id: deputyId,
      skill_id: skillId,
      target_id: targetId,
      mp_consumed: 10,
      remaining_mp: deputy.mp - 10,
    };
  }

  /**
   * 升级副将技能
   * @param deputyId 副将ID
   * @param skillId 技能ID
   * @param costItems 升级消耗物品（暂未实现）
   * @param playerId 玩家ID
   * @returns 技能升级结果，包含升级前后的等级
   */
  async upgradeSkill(
    deputyId: number,
    skillId: number,
    costItems: any[],
    playerId: number
  ) {
    const deputy = await this.getDeputyDetail(deputyId, playerId);

    const learnedSkill = await this.deputyGeneralSkillLearnedRepository.findOne(
      {
        where: { deputy_id: deputyId, skill_id: skillId },
      }
    );

    if (!learnedSkill) {
      throw new BadRequestException("技能未学习", "1016");
    }

    // 等级门槛：30/50/70 决定普通技能最高可升 3/4/5 级
    const allowedMaxGrade = (lvl: number): number => {
      if (lvl >= 70) return 5;
      if (lvl >= 50) return 4;
      if (lvl >= 30) return 3;
      return 2;
    };
    const maxGrade = allowedMaxGrade(deputy.lvl);
    const nextGrade = learnedSkill.grade + 1;
    if (nextGrade > maxGrade) {
      throw new BadRequestException(
        `当前等级不足，无法升至 ${nextGrade} 级技能`,
        "LEVEL_LIMIT"
      );
    }

    await this.deputyGeneralSkillLearnedRepository.update(
      { deputy_id: deputyId, skill_id: skillId },
      { grade: nextGrade }
    );

    return {
      deputy_id: deputyId,
      skill_id: skillId,
      old_grade: learnedSkill.grade,
      new_grade: nextGrade,
    };
  }

  /**
   * 副将学习新技能
   * @param deputyId 副将ID
   * @param skillId 技能ID
   * @param playerId 玩家ID
   * @returns 学习技能结果，包含技能名称和等级
   */
  async learnSkill(deputyId: number, skillId: number, playerId: number) {
    const deputy = await this.getDeputyDetail(deputyId, playerId);

    const skill = await this.skillBaseRepository.findOne({
      where: { id: skillId },
    });
    if (!skill) {
      throw new BadRequestException("技能不存在", "1018");
    }

    const existingSkill =
      await this.deputyGeneralSkillLearnedRepository.findOne({
        where: { deputy_id: deputyId, skill_id: skillId },
      });

    if (existingSkill) {
      throw new BadRequestException("技能已学习", "1006");
    }

    const skillCount = await this.deputyGeneralSkillLearnedRepository.count({
      where: { deputy_id: deputyId },
    });

    if (skillCount >= 4) {
      throw new BadRequestException("副将技能数量已达上限", "1006");
    }

    const newSkill = this.deputyGeneralSkillLearnedRepository.create({
      deputy_id: deputyId,
      skill_id: skillId,
      grade: 1,
      order: skillCount + 1,
      use_count: 0,
      hua: 0,
    });

    await this.deputyGeneralSkillLearnedRepository.save(newSkill);

    // 学习后，同步职业为技能所属职业
    await this.deputyGeneralRepository.update(deputyId, {
      roleType: skill.type,
      updated_at: new Date(),
    });

    return {
      deputy_id: deputyId,
      skill_id: skillId,
      skill_name: skill.name,
      grade: 1,
    };
  }

  /**
   * action=1 的学习逻辑：支持 skillId=0/undefined 随机学习，并同步职业
   */
  async learnSkillDynamic(
    playerId: number,
    deputyId: number,
    skillId?: number
  ): Promise<{
    deputy_id: number;
    skill_id: number;
    skill_name: string;
    role_type: number;
    msg: string;
  }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const pd = await queryRunner.manager.findOne(PlayerDeputy, {
        where: { deputy_id: deputyId, player_id: playerId },
      });
      if (!pd) throw new BadRequestException("副将不属于当前玩家", "1002");
      const deputy = await queryRunner.manager.findOne(DeputyGeneral, {
        where: { id: deputyId },
        relations: ["base"],
      } as any);
      if (!deputy) throw new NotFoundException("副将不存在", "1001");

      // 计数上限
      const skillCount = await queryRunner.manager.count(
        DeputyGeneralSkillLearned,
        { where: { deputy_id: deputyId } }
      );
      if (skillCount >= 4) {
        throw new BadRequestException("副将技能数量已达上限", "1006");
      }

      // 选择技能
      let targetSkill: SkillBase | null = null;
      if (skillId && Number(skillId) > 0) {
        targetSkill = await queryRunner.manager.findOne(SkillBase, {
          where: { id: Number(skillId) },
        });
        if (!targetSkill) throw new BadRequestException("技能不存在", "1018");
      } else {
        const qb = queryRunner.manager
          .getRepository(SkillBase)
          .createQueryBuilder("s")
          .where("s.type IN (:...types)", { types: [1, 2, 3] })
          .orderBy("RAND()")
          .limit(1);
        targetSkill = (await qb.getOne()) as SkillBase | null;
        if (!targetSkill) throw new BadRequestException("暂无可用技能", "1018");
      }

      // 重复校验
      const existed = await queryRunner.manager.findOne(
        DeputyGeneralSkillLearned,
        { where: { deputy_id: deputyId, skill_id: targetSkill.id } }
      );
      if (existed) {
        throw new BadRequestException("技能已学习", "1006");
      }

      // 新增技能
      const learned = queryRunner.manager.create(DeputyGeneralSkillLearned, {
        deputy_id: deputyId,
        skill_id: targetSkill.id,
        grade: 1,
        order: skillCount + 1,
        use_count: 0,
        hua: 0,
        created_at: new Date(),
        updated_at: new Date(),
      });
      await queryRunner.manager.save(DeputyGeneralSkillLearned, learned);

      // 同步职业
      await queryRunner.manager.update(DeputyGeneral, deputyId, {
        roleType: targetSkill.type,
        updated_at: new Date(),
      });

      await queryRunner.commitTransaction();

      const name = deputy.base?.name || "副将";
      const roleMap: Record<number, string> = {
        1: "武士",
        2: "文人",
        3: "异师",
      };
      const roleName = roleMap[targetSkill.type] || "未知";
      const msg = `您的副将${name}成功学到了[${targetSkill.name}],他现在的职业是${roleName},以后在战斗中使用会增加熟练度!`;
      return {
        deputy_id: deputyId,
        skill_id: targetSkill.id,
        skill_name: targetSkill.name,
        role_type: targetSkill.type,
        msg,
      };
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw e;
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * 升级副将星级
   * @param deputyId 副将ID
   * @param costItems 升级消耗物品（暂未实现）
   * @param playerId 玩家ID
   * @returns 星级升级结果，包含升级前后的星级
   */
  async upgradeStar(deputyId: number, costItems: any[], playerId: number) {
    const deputy = await this.getDeputyDetail(deputyId, playerId);

    if (deputy.star >= 5) {
      throw new BadRequestException("副将星级已达上限", "1004");
    }

    await this.deputyGeneralRepository.update(deputyId, {
      star: deputy.star + 1,
    });

    return {
      deputy_id: deputyId,
      old_star: deputy.star,
      new_star: deputy.star + 1,
    };
  }

  /**
   * 副将转职（重置等级并提升成长率）
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 转职结果，包含等级重置和成长率提升信息
   */
  async transform(deputyId: number, playerId: number) {
    const deputy = await this.getDeputyDetail(deputyId, playerId);

    if (deputy.lvl < 100) {
      throw new BadRequestException("副将等级不足", "1003");
    }

    if (deputy.trans_count >= 4) {
      throw new BadRequestException("副将转职次数已达上限", "1005");
    }

    const newCzl = parseFloat(
      (parseFloat(deputy.czl.toString()) + 0.1).toFixed(2)
    );

    await this.deputyGeneralRepository.update(deputyId, {
      lvl: 1,
      exp: 0,
      trans_count: deputy.trans_count + 1,
      czl: newCzl,
    });

    await this.deputyGeneralSkillLearnedRepository.delete({
      deputy_id: deputyId,
    });

    return {
      deputy_id: deputyId,
      old_level: deputy.lvl,
      new_level: 1,
      old_trans: deputy.trans_count,
      new_trans: deputy.trans_count + 1,
      new_czl: newCzl,
    };
  }

  /**
   * 解雇副将（删除副将及相关数据）
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 解雇结果
   */
  async dismiss(deputyId: number, playerId: number) {
    await this.getDeputyDetail(deputyId, playerId);

    await this.playerDeputyRepository.delete({
      deputy_id: deputyId,
      player_id: playerId,
    });
    await this.deputyGeneralSkillLearnedRepository.delete({
      deputy_id: deputyId,
    });
    await this.deputyGeneralRepository.delete(deputyId);

    return { deputy_id: deputyId, dismissed: true };
  }

  /**
   * 重新训练副将（重新随机生成属性）
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 重新训练结果，包含新的属性值
   */
  async retrain(deputyId: number, playerId: number) {
    const deputy = await this.getDeputyDetail(deputyId, playerId);

    const base = await this.deputyGeneralBaseRepository.findOne({
      where: { id: deputy.base_id },
    });

    if (!base) {
      throw new BadRequestException("基础副将数据不存在", "1022");
    }

    const newAp = this.getRandomValue(base.ap_min, base.ap_max);
    const newHp = this.getRandomValue(base.hp_min, base.hp_max);
    const newMp = this.getRandomValue(base.mp_min, base.mp_max);
    const newSp = this.getRandomValue(base.sp_min, base.sp_max);
    const newCzl = this.getRandomDecimal(base.czl_min, base.czl_max);

    await this.deputyGeneralRepository.update(deputyId, {
      ap: newAp,
      hp: newHp,
      mp: newMp,
      sp: newSp,
      czl: newCzl,
    });

    return {
      deputy_id: deputyId,
      new_attributes: {
        ap: newAp,
        hp: newHp,
        mp: newMp,
        sp: newSp,
        czl: newCzl,
      },
    };
  }

  /**
   * 碎片合成副将：消耗10个对应碎片道具，生成对应基础副将并发放给玩家
   * @param characterId 角色ID
   * @param gid 碎片物品itemId（如：602 小姐姐虎符）
   */
  async composeDeputyFromFragment(
    characterId: number,
    gid: number
  ): Promise<{ deputy_id: number; base_id: number; is_in_warehouse: boolean }> {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      // 1) 校验背包碎片数量 >= 10
      const inv = await queryRunner.manager.findOne(CharacterInventoryEntity, {
        where: { characterId, itemId: gid },
      });
      const currentNum = Number((inv as any)?.num || 0);
      if (!inv || currentNum < 10) {
        throw new BadRequestException(
          "碎片数量不足(需要10个)",
          "NOT_ENOUGH_FRAGMENT"
        );
      }

      // 2) 建立 gid -> 基础副将名称 的映射（按物品约定）
      const gidToBaseName: Record<number, string> = {
        601: "关羽",
        602: "小姐姐",
        603: "小哥哥",
        604: "水镜先生",
        606: "貂蝉",
        609: "童渊",
        610: "南华仙人",
        611: "测试副将",
      };
      const baseName = gidToBaseName[Number(gid)];
      if (!baseName) {
        throw new BadRequestException(
          "未知碎片，不支持合成",
          "UNKNOWN_FRAGMENT"
        );
      }

      const base = await queryRunner.manager.findOne(DeputyGeneralBase, {
        where: { name: baseName },
      } as any);
      if (!base) {
        throw new BadRequestException("基础副将不存在", "BASE_NOT_FOUND");
      }

      // 3) 扣除10个碎片
      const newNum = currentNum - 10;
      await queryRunner.manager.update(
        CharacterInventoryEntity,
        { id: (inv as any).id },
        newNum > 0
          ? { num: newNum, updated_at: new Date() }
          : { num: 0, status: 0, updated_at: new Date() }
      );

      // 4) 生成副将并发放（沿用 generateDeputy 逻辑的核心）
      const deputy = new DeputyGeneral();
      (deputy as any).base_id = (base as any).id;
      deputy.czl = 1.0 as any;
      deputy.sp = 10;
      deputy.ap = 10;
      deputy.hp = 10;
      deputy.mp = 10;
      deputy.sp_points = 0;
      deputy.ap_points = 0;
      deputy.hp_points = 0;
      deputy.mp_points = 0;
      deputy.loyalty = 100;
      deputy.compatibility = 0;
      deputy.is_real = true as any;
      deputy.trans_count = 0;
      deputy.roleType = Math.floor(Math.random() * 3) + 1;
      deputy.star = 0;
      deputy.lvl = 0;
      deputy.exp = 100 as any;
      deputy.ultimate_skill_1_id = null as any;
      deputy.ultimate_skill_1_level = 0;
      deputy.ultimate_skill_2_id = null as any;
      deputy.ultimate_skill_2_level = 0;
      deputy.created_at = new Date();
      deputy.updated_at = new Date();
      const saved = await queryRunner.manager.save(DeputyGeneral, deputy);

      // 入玩家副将或仓库
      const count = await queryRunner.manager.count(PlayerDeputy, {
        where: { player_id: characterId },
      });
      let isInWarehouse = false;
      if (count >= 10) {
        await queryRunner.manager.insert(PlayerDeputyWarehouse, {
          player_id: characterId,
          deputy_id: (saved as any).id,
        });
        isInWarehouse = true;
      } else {
        await queryRunner.manager.insert(PlayerDeputy, {
          player_id: characterId,
          deputy_id: (saved as any).id,
          pos: 0,
        });
      }

      await queryRunner.commitTransaction();
      return {
        deputy_id: (saved as any).id,
        base_id: (base as any).id,
        is_in_warehouse: isInWarehouse,
      };
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw e;
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * 培养副将默契值
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 默契值培养结果，包含消耗金币和增加的默契值
   */
  async cultivateMqd(deputyId: number, playerId: number) {
    const deputy = await this.getDeputyDetail(deputyId, playerId);

    if (deputy.compatibility >= 200000) {
      throw new BadRequestException("默契值已达上限", "1020");
    }

    const newCompatibility = Math.min(deputy.compatibility + 1000, 200000);

    await this.deputyGeneralRepository.update(deputyId, {
      compatibility: newCompatibility,
    });

    return {
      deputy_id: deputyId,
      old_mqd: deputy.compatibility,
      new_mqd: newCompatibility,
      cost_gold: 90,
      mqd_increased: newCompatibility - deputy.compatibility,
    };
  }

  /**
   * 根据星级类型获取基础副将列表
   * @param starLevel 星级类型（1:国土, 2:将才, 3:英才, 4:常人）
   * @returns 对应星级的基础副将列表
   */
  async getBaseDeputiesByStarLevel(starLevel: number) {
    try {
      const baseDeputies = await this.deputyGeneralBaseRepository.find({
        where: { star_level: starLevel },
      });

      console.log(
        `查询到${baseDeputies.length}个star_level=${starLevel}的基础副将`
      );
      return baseDeputies;
    } catch (error) {
      console.error("查询基础副将失败:", error);
      return [];
    }
  }

  /**
   * 根据星级查询副将列表（支持分页和排序）
   * @param starLevel 星级
   * @param sortType 排序类型 (1: 成长最高, 2: 血最高, 3: 精最高, 4: 攻最高, 5: 速最高)
   * @param pageNum 页码（从0开始）
   * @param pageSize 每页数量（默认20）
   * @returns 分页查询结果
   */
  async getDeputyGeneralsByStarLevel(
    starLevel: number,
    sortType: number,
    pageNum: number = 0,
    pageSize: number = 100
  ) {
    try {
      // 构建查询条件
      const whereCondition = { star_level: starLevel };

      // 构建排序条件
      let orderCondition: any = {};
      switch (sortType) {
        case 1: // 成长最高（按czl_max降序）
          orderCondition = { czl_max: "DESC" };
          break;
        case 2: // 血最高（按hp_max降序）
          orderCondition = { hp_max: "DESC" };
          break;
        case 3: // 精最高（按mp_max降序）
          orderCondition = { mp_max: "DESC" };
          break;
        case 4: // 攻最高（按ap_max降序）
          orderCondition = { ap_max: "DESC" };
          break;
        case 5: // 速最高（按sp_max降序）
          orderCondition = { sp_max: "DESC" };
          break;
        default:
          orderCondition = { ap_max: "DESC" }; // 默认按攻击力降序
      }

      // 计算分页参数
      const skip = pageNum * pageSize;

      // 执行分页查询
      const [deputies, totalCount] =
        await this.deputyGeneralBaseRepository.findAndCount({
          where: whereCondition,
          order: orderCondition,
          skip: skip,
          take: pageSize,
        });

      // 计算总页数
      const totalPages = Math.ceil(totalCount / pageSize);

      // 格式化返回数据，按照文档要求
      const formattedList = deputies.map((deputy) => {
        // 根据排序类型显示对应的属性范围
        let attrRange = "";
        switch (sortType) {
          case 1: // 成长最高
            attrRange = `(${deputy.czl_min}-${deputy.czl_max})`;
            break;
          case 2: // 血最高
            attrRange = `(${deputy.hp_min}-${deputy.hp_max})`;
            break;
          case 3: // 精最高
            attrRange = `(${deputy.mp_min}-${deputy.mp_max})`;
            break;
          case 4: // 攻最高
            attrRange = `(${deputy.ap_min}-${deputy.ap_max})`;
            break;
          case 5: // 速最高
            attrRange = `(${deputy.sp_min}-${deputy.sp_max})`;
            break;
          default:
            attrRange = `(${deputy.ap_min}-${deputy.ap_max})`; // 默认显示攻击力范围
        }

        return {
          id: deputy.id,
          name: deputy.name,
          attr: attrRange,
        };
      });

      console.log(
        `查询副将列表成功: 星级=${starLevel}, 排序=${sortType}, 页码=${pageNum}, 总数=${totalCount}, 当前页=${deputies.length}`
      );

      return {
        list: formattedList,
        page: pageNum,
        pageSize: pageSize,
        totalCount: totalCount,
        totalPages: totalPages,
        hasNext: pageNum < totalPages - 1,
        hasPrev: pageNum > 0,
      };
    } catch (error: any) {
      console.error("查询副将列表失败:", error);
      throw new Error(`查询副将列表失败: ${error.message}`);
    }
  }

  /**
   * 根据ID查询副将详情
   * @param deputyId 副将ID
   * @returns 副将详情信息
   */
  async getDeputyGeneralById(deputyId: number) {
    try {
      const deputy = await this.deputyGeneralBaseRepository.findOne({
        where: { id: deputyId },
      });

      if (!deputy) {
        throw new Error("副将不存在");
      }

      // 按照文档格式返回数据
      const formattedData = {
        name: deputy.name,
        s: deputy.star_level,
        ap: `${deputy.ap_min}-${deputy.ap_max}`,
        czl: `${deputy.czl_min}-${deputy.czl_max}`,
        hp: `${deputy.hp_min}-${deputy.hp_max}`,
        mp: `${deputy.mp_min}-${deputy.mp_max}`,
        sp: `${deputy.sp_min}-${deputy.sp_max}`,
        descr: deputy.description,
      };

      console.log(`查询副将详情成功: ID=${deputyId}, 名称=${deputy.name}`);

      return formattedData;
    } catch (error: any) {
      console.error("查询副将详情失败:", error);
      throw new Error(`查询副将详情失败: ${error.message}`);
    }
  }

  /**
   * 生成新副将（根据基础副将数据创建）
   * @param baseId 基础副将ID
   * @param targetPlayerId 目标玩家ID
   * @returns 生成的副将信息，包含属性值和是否在仓库中
   */
  async generateDeputy(baseId: number, targetPlayerId: number) {
    const base = await this.deputyGeneralBaseRepository.findOne({
      where: { id: baseId },
    });

    if (!base) {
      throw new BadRequestException("基础副将不存在", "1022");
    }

    const ap = this.getRandomValue(base.ap_min, base.ap_max);
    const hp = this.getRandomValue(base.hp_min, base.hp_max);
    const mp = this.getRandomValue(base.mp_min, base.mp_max);
    const sp = this.getRandomValue(base.sp_min, base.sp_max);
    const czl = this.getRandomDecimal(base.czl_min, base.czl_max);

    const deputy = new DeputyGeneral();
    Object.assign(deputy, {
      base_id: baseId, // 基础副将ID
      czl: czl, // 成长率
      sp: sp, // 速度
      ap: ap, // 攻击力
      hp: hp, // 血量
      mp: mp, // 精力
      sp_points: 0, // 加点速点数
      ap_points: 0, // 加点攻点数
      hp_points: 0, // 加点血点数
      mp_points: 0, // 加点精点数
      loyalty: 100, // 忠诚度
      compatibility: 0, // 默契度
      is_real: true, // 是否为真
      trans_count: 0, // 转职次数
      roleType: Math.floor(Math.random() * 3) + 1, // 职业类型(1:武士, 2:文人, 3:异师)
      star: 0, // 星级
      lvl: 0, // 等级
      exp: 100, // 升级还需要的经验值
      ultimate_skill_1_id: null, // 无双1id
      ultimate_skill_1_level: 0, // 无双1等级
      ultimate_skill_2_id: null, // 无双2id
      ultimate_skill_2_level: 0, // 无双2等级
    });

    const savedDeputy = (await this.deputyGeneralRepository.save(
      deputy
    )) as DeputyGeneral;

    const playerDeputyCount = await this.playerDeputyRepository.count({
      where: { player_id: targetPlayerId },
    });

    let isInWarehouse = false;

    if (playerDeputyCount >= 10) {
      // 放入仓库逻辑 - 实际添加到仓库表
      const warehouseEntry = this.playerDeputyWarehouseRepository.create({
        player_id: targetPlayerId,
        deputy_id: savedDeputy.id,
      });
      await this.playerDeputyWarehouseRepository.save(warehouseEntry);
      isInWarehouse = true;
    } else {
      const playerDeputy = this.playerDeputyRepository.create({
        player_id: targetPlayerId,
        deputy_id: savedDeputy.id,
        pos: 0, // 初始位置为0（未上阵）
      });
      await this.playerDeputyRepository.save(playerDeputy);
    }

    return {
      deputy_id: savedDeputy.id,
      base_id: baseId,
      player_id: targetPlayerId,
      name: savedDeputy.base?.name || "未知副将",
      level: savedDeputy.lvl,
      star: savedDeputy.star,
      ap: savedDeputy.ap,
      hp: savedDeputy.hp,
      mp: savedDeputy.mp,
      sp: savedDeputy.sp,
      czl: savedDeputy.czl,
      role_type: savedDeputy.roleType,
      is_in_warehouse: isInWarehouse,
      generated_attributes: { ap, hp, mp, sp, czl },
    };
  }

  /**
   * 副将上阵操作 (act: 4)
   * 如果已有三个副将上阵，需要移除 pos 为 3 的副将下阵，将当前副将上阵并设置 pos 为 3
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 上阵操作结果
   */
  async deployDeputyToBattle(deputyId: number, playerId: number) {
    const playerDeputy = await this.playerDeputyRepository.findOne({
      where: { deputy_id: deputyId, player_id: playerId },
    });

    if (!playerDeputy) {
      throw new BadRequestException("副将不属于当前玩家", "1002");
    }

    // 查询副将基础，判断是否为国士（star_level = 1）
    const deputy = await this.deputyGeneralRepository.findOne({
      where: { id: deputyId },
      relations: ["base"],
    });
    if (!deputy) {
      throw new BadRequestException("副将不存在", "1006");
    }

    // 检查当前上阵的副将数量
    const deployedDeputies = await this.playerDeputyRepository.find({
      where: {
        player_id: playerId,
        pos: In([1, 2, 3]),
      },
    });

    // 如果当前上阵的是国士（基础星级=1），不允许同基础副将同时上阵
    // 若已有同基础副将上阵，则直接顶替其位置（被顶替者下阵）
    if (
      deputy.base &&
      deputy.base.star_level === 1 &&
      deployedDeputies.length > 0
    ) {
      const deployedIds = deployedDeputies.map((d) => d.deputy_id);
      const deployedGenerals = await this.deputyGeneralRepository.find({
        where: { id: In(deployedIds) },
      });
      const sameBaseDeployed = deployedGenerals.find(
        (g) => g.base_id === deputy.base_id
      );
      if (sameBaseDeployed) {
        const target = deployedDeputies.find(
          (d) => d.deputy_id === sameBaseDeployed.id
        );
        const targetPos = target?.pos || 1;
        // 将已上阵同基础副将下阵
        await this.playerDeputyRepository.update(
          { deputy_id: sameBaseDeployed.id, player_id: playerId },
          { pos: 0 }
        );
        // 将当前副将上阵到该位置
        await this.playerDeputyRepository.update(
          { deputy_id: deputyId, player_id: playerId },
          { pos: targetPos }
        );
        return {
          deputy_id: deputyId,
          pos: targetPos,
          replaced: sameBaseDeployed.id,
        };
      }
    }

    if (deployedDeputies.length >= 3) {
      // 如果已有三个副将上阵，移除 pos 为 3 的副将
      const pos3Deputy = deployedDeputies.find((d) => d.pos === 3);
      if (pos3Deputy) {
        await this.playerDeputyRepository.update(
          { deputy_id: pos3Deputy.deputy_id, player_id: playerId },
          { pos: 0 }
        );
      }
    }

    // 将当前副将上阵并设置 pos 为 3
    await this.playerDeputyRepository.update(
      { deputy_id: deputyId, player_id: playerId },
      { pos: 3 }
    );

    return { deputy_id: deputyId, pos: 3, is_deployed: true };
  }

  /**
   * 副将位置交换 (act: 3)
   * 当前上阵副将位置上移一位，与上一个位置的副将交换 pos 位置
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 位置交换结果
   */
  async swapDeputyPosition(deputyId: number, playerId: number) {
    const playerDeputy = await this.playerDeputyRepository.findOne({
      where: { deputy_id: deputyId, player_id: playerId },
    });

    if (!playerDeputy) {
      throw new BadRequestException("副将不属于当前玩家", "1002");
    }

    if (playerDeputy.pos <= 1) {
      throw new BadRequestException("副将已在最前位置，无法上移", "1003");
    }

    // 找到上一个位置的副将
    const prevPosDeputy = await this.playerDeputyRepository.findOne({
      where: { player_id: playerId, pos: playerDeputy.pos - 1 },
    });

    if (!prevPosDeputy) {
      throw new BadRequestException("未找到上一个位置的副将", "1004");
    }

    // 交换位置
    const currentPos = playerDeputy.pos;
    const prevPos = prevPosDeputy.pos;

    await this.playerDeputyRepository.update(
      { deputy_id: deputyId, player_id: playerId },
      { pos: prevPos }
    );

    await this.playerDeputyRepository.update(
      { deputy_id: prevPosDeputy.deputy_id, player_id: playerId },
      { pos: currentPos }
    );

    return {
      deputy_id: deputyId,
      new_pos: prevPos,
      swapped_with: prevPosDeputy.deputy_id,
      swapped_pos: currentPos,
    };
  }

  /**
   * 副将下阵 (act: 2)
   * 副将下阵，清空 pos，并根据 pos 重新排序剩余上阵副将
   * @param deputyId 副将ID
   * @param playerId 玩家ID
   * @returns 下阵操作结果
   */
  async removeDeputyFromBattle(deputyId: number, playerId: number) {
    const playerDeputy = await this.playerDeputyRepository.findOne({
      where: { deputy_id: deputyId, player_id: playerId },
    });

    if (!playerDeputy) {
      throw new BadRequestException("副将不属于当前玩家", "1002");
    }

    if (playerDeputy.pos === 0) {
      throw new BadRequestException("副将未上阵", "1005");
    }

    const removedPos = playerDeputy.pos;

    // 将当前副将下阵
    await this.playerDeputyRepository.update(
      { deputy_id: deputyId, player_id: playerId },
      { pos: 0 }
    );

    // 重新排序剩余上阵副将的 pos
    const remainingDeployedDeputies = await this.playerDeputyRepository.find({
      where: {
        player_id: playerId,
        pos: In([1, 2, 3]),
      },
      order: { pos: "ASC" },
    });

    // 重新分配 pos 从 1 开始
    for (let i = 0; i < remainingDeployedDeputies.length; i++) {
      const newPos = i + 1;
      if (remainingDeployedDeputies[i].pos !== newPos) {
        await this.playerDeputyRepository.update(
          {
            deputy_id: remainingDeployedDeputies[i].deputy_id,
            player_id: playerId,
          },
          { pos: newPos }
        );
      }
    }

    return {
      deputy_id: deputyId,
      removed_pos: removedPos,
      remaining_count: remainingDeployedDeputies.length,
    };
  }

  /**
   * 设置副将上阵/下阵状态（兼容旧方法）
   * @param deputyId 副将ID
   * @param isDeployed 是否上阵
   * @param playerId 玩家ID
   * @returns 上阵状态设置结果
   */
  async deployDeputy(deputyId: number, isDeployed: boolean, playerId: number) {
    const playerDeputy = await this.playerDeputyRepository.findOne({
      where: { deputy_id: deputyId, player_id: playerId },
    });

    if (!playerDeputy) {
      throw new BadRequestException("副将不属于当前玩家", "1002");
    }

    await this.playerDeputyRepository.update(
      { deputy_id: deputyId, player_id: playerId },
      { pos: isDeployed ? 1 : 0 }
    );

    return { deputy_id: deputyId, is_deployed: isDeployed };
  }

  /**
   * 查看副将列表（1419）- 包括可以放到仓库的副将和仓库中的副将
   * @param action 操作类型：0-查看可以放到仓库的副将列表，2-查看仓库中的副将列表
   * @param pageNum 页码（暂未使用）
   * @param sort 分类：根据副将基础表star_level，0默认为全部类型
   * @param playerId 玩家ID
   * @returns 副将列表
   */
  async getDeputyWarehouseList(
    action: number,
    pageNum: number,
    sort: number,
    playerId: number
  ) {
    if (action === 0) {
      // 查看可以放到仓库的副将列表（玩家副将表，未上阵的副将）
      const queryBuilder = this.playerDeputyRepository
        .createQueryBuilder("playerDeputy")
        .leftJoinAndSelect("playerDeputy.deputy", "deputy")
        .leftJoinAndSelect("deputy.base", "base")
        .where("playerDeputy.player_id = :playerId", { playerId })
        .andWhere("playerDeputy.pos = 0"); // 只获取未上阵的副将

      // 如果指定了分类，按star_level过滤
      if (sort > 0) {
        queryBuilder.andWhere("base.star_level = :sort", { sort });
      }

      const playerDeputies = await queryBuilder.getMany();

      const deputies = playerDeputies.map((pd) => ({
        id: pd.deputy.id,
        lvl: pd.deputy.lvl,
        name: pd.deputy.base?.name || "未知副将",
        roleType: pd.deputy.roleType,
        s: pd.deputy.base?.star_level || 0,
        star: pd.deputy.star,
      }));

      return {
        list: deputies,
        sum: deputies.length,
        type: 0,
      };
    } else if (action === 2) {
      // 查询本角色可以从仓库提取的副将列表
      const queryBuilder = this.playerDeputyWarehouseRepository
        .createQueryBuilder("warehouse")
        .leftJoinAndSelect("warehouse.deputy", "deputy")
        .leftJoinAndSelect("deputy.base", "base")
        .where("warehouse.player_id = :playerId", { playerId });

      // 如果指定了分类，按star_level过滤
      if (sort > 0) {
        queryBuilder.andWhere("base.star_level = :sort", { sort });
      }

      const warehouseDeputies = await queryBuilder.getMany();

      const deputies = warehouseDeputies.map((wd) => ({
        id: wd.deputy.id,
        lvl: wd.deputy.lvl,
        name: wd.deputy.base?.name || "未知副将",
        roleType: wd.deputy.roleType,
        s: wd.deputy.base?.star_level || 0,
        star: wd.deputy.star,
      }));

      return {
        list: deputies,
        sum: deputies.length,
        type: 2,
      };
    } else {
      throw new BadRequestException("无效的操作类型", "1018");
    }
  }

  /**
   * 副将仓库操作（1420）- 存储到仓库和从仓库提取
   * @param deputyId 副将ID
   * @param action 操作类型：1-存储到仓库，2-从仓库提取
   * @param pageNum 页码（暂未使用）
   * @param playerId 玩家ID
   * @returns 仓库操作结果
   */
  async deputyWarehouseOperation(
    deputyId: number,
    action: number,
    pageNum: number,
    playerId: number
  ) {
    if (action === 1) {
      // 将副将从副将列表放到仓库（玩家副将表id删除，玩家副将仓库表新增）
      return await this.deputyGeneralRepository.manager.transaction(
        async (transactionalEntityManager) => {
          // 检查副将是否属于当前玩家且未上阵
          const playerDeputy = await transactionalEntityManager.findOne(
            PlayerDeputy,
            {
              where: { deputy_id: deputyId, player_id: playerId, pos: 0 },
            }
          );

          if (!playerDeputy) {
            throw new BadRequestException("副将不存在或已上阵", "1001");
          }

          // 从玩家副将表中删除
          await transactionalEntityManager.delete(PlayerDeputy, {
            deputy_id: deputyId,
            player_id: playerId,
          });

          // 添加到仓库表
          const warehouseEntry = transactionalEntityManager.create(
            PlayerDeputyWarehouse,
            {
              player_id: playerId,
              deputy_id: deputyId,
            }
          );
          await transactionalEntityManager.save(
            PlayerDeputyWarehouse,
            warehouseEntry
          );

          return {
            deputy_id: deputyId,
            action: 1,
            msg: "存储成功！",
          };
        }
      );
    } else if (action === 2) {
      // 将副将从仓库提取当副将列表，需要校验玩家副将表数量小于10才能提取
      return await this.deputyGeneralRepository.manager.transaction(
        async (transactionalEntityManager) => {
          // 检查仓库中是否有该副将
          const warehouseEntry = await transactionalEntityManager.findOne(
            PlayerDeputyWarehouse,
            {
              where: { deputy_id: deputyId, player_id: playerId },
            }
          );

          if (!warehouseEntry) {
            throw new BadRequestException("仓库中不存在该副将", "1001");
          }

          // 检查玩家副将表数量是否小于10
          const playerDeputyCount = await transactionalEntityManager.count(
            PlayerDeputy,
            {
              where: { player_id: playerId },
            }
          );

          if (playerDeputyCount >= 10) {
            throw new BadRequestException("副将列表已满，无法提取", "1006");
          }

          // 从仓库表中删除
          await transactionalEntityManager.delete(PlayerDeputyWarehouse, {
            deputy_id: deputyId,
            player_id: playerId,
          });

          // 添加到玩家副将表
          const playerDeputy = transactionalEntityManager.create(PlayerDeputy, {
            player_id: playerId,
            deputy_id: deputyId,
            pos: 0, // 初始位置为0（未上阵）
          });
          await transactionalEntityManager.save(PlayerDeputy, playerDeputy);

          return {
            deputy_id: deputyId,
            action: 2,
            msg: "提取成功！",
          };
        }
      );
    } else {
      throw new BadRequestException("无效的操作类型", "1018");
    }
  }

  /**
   * 生成指定范围内的随机整数
   * @param min 最小值
   * @param max 最大值
   * @returns 随机整数
   */
  private getRandomValue(min: number, max: number): number {
    // 确保输入参数是数字类型
    const minNum = Number(min);
    const maxNum = Number(max);

    // 如果转换失败，使用默认值
    if (isNaN(minNum) || isNaN(maxNum)) {
      console.warn("getRandomValue: 无效的输入参数", { min, max });
      return Math.floor(Math.random() * 100) + 1; // 默认随机值
    }

    return Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum;
  }

  /**
   * 生成指定范围内的随机小数（保留2位小数）
   * @param min 最小值
   * @param max 最大值
   * @returns 随机小数
   */
  private getRandomDecimal(min: number, max: number): number {
    // 确保输入参数是数字类型
    const minNum = Number(min);
    const maxNum = Number(max);

    // 如果转换失败，使用默认值
    if (isNaN(minNum) || isNaN(maxNum)) {
      console.warn("getRandomDecimal: 无效的输入参数", { min, max });
      return 1.0; // 默认成长率
    }

    const randomValue = Math.random() * (maxNum - minNum) + minNum;
    return parseFloat(randomValue.toFixed(2));
  }

  /**
   * 使用事务生成副将并扣除物品
   * @param baseId 基础副将ID
   * @param targetPlayerId 目标玩家ID
   * @param inventoryItemId 背包物品ID
   * @param newQuantity 新的物品数量
   * @returns 生成的副将信息
   */
  async generateDeputyWithTransaction(
    baseId: number,
    targetPlayerId: number,
    inventoryItemId: number,
    newQuantity: number
  ) {
    return await this.deputyGeneralRepository.manager.transaction(
      async (transactionalEntityManager) => {
        // 1. 生成副将
        const base = await transactionalEntityManager.findOne(
          DeputyGeneralBase,
          {
            where: { id: baseId },
          }
        );

        if (!base) {
          throw new BadRequestException("基础副将不存在", "1022");
        }

        const ap = this.getRandomValue(base.ap_min, base.ap_max);
        const hp = this.getRandomValue(base.hp_min, base.hp_max);
        const mp = this.getRandomValue(base.mp_min, base.mp_max);
        const sp = this.getRandomValue(base.sp_min, base.sp_max);
        const czl = this.getRandomDecimal(base.czl_min, base.czl_max);

        const deputy = new DeputyGeneral();
        Object.assign(deputy, {
          base_id: baseId,
          czl: czl,
          sp: sp,
          ap: ap,
          hp: hp,
          mp: mp,
          sp_points: 0,
          ap_points: 0,
          hp_points: 0,
          mp_points: 0,
          loyalty: 100,
          compatibility: 0,
          is_real: true,
          trans_count: 0,
          roleType: Math.floor(Math.random() * 3) + 1,
          star: 0,
          lvl: 1,
          exp: 0,
          ultimate_skill_1_id: null,
          ultimate_skill_1_level: 0,
          ultimate_skill_2_id: null,
          ultimate_skill_2_level: 0,
        });

        const savedDeputy = await transactionalEntityManager.save(
          DeputyGeneral,
          deputy
        );

        // 2. 检查玩家副将数量并决定是否放入仓库
        const playerDeputyCount = await transactionalEntityManager.count(
          PlayerDeputy,
          {
            where: { player_id: targetPlayerId },
          }
        );

        let isInWarehouse = false;

        if (playerDeputyCount >= 10) {
          // 放入仓库逻辑 - 实际添加到仓库表
          const warehouseEntry = transactionalEntityManager.create(
            PlayerDeputyWarehouse,
            {
              player_id: targetPlayerId,
              deputy_id: savedDeputy.id,
            }
          );
          await transactionalEntityManager.save(
            PlayerDeputyWarehouse,
            warehouseEntry
          );
          isInWarehouse = true;
        } else {
          const playerDeputy = transactionalEntityManager.create(PlayerDeputy, {
            player_id: targetPlayerId,
            deputy_id: savedDeputy.id,
            pos: 0,
          });
          await transactionalEntityManager.save(PlayerDeputy, playerDeputy);
        }

        // 3. 扣除背包物品
        await transactionalEntityManager.update(
          CharacterInventoryEntity,
          inventoryItemId,
          { num: newQuantity }
        );

        // 4. 如果数量为0，标记为已使用
        if (newQuantity === 0) {
          await transactionalEntityManager.update(
            CharacterInventoryEntity,
            inventoryItemId,
            { status: 0 }
          );
        }

        return {
          deputy_id: savedDeputy.id,
          base_id: baseId,
          player_id: targetPlayerId,
          name: base.name || "未知副将",
          level: savedDeputy.lvl,
          star: savedDeputy.star,
          ap: savedDeputy.ap,
          hp: savedDeputy.hp,
          mp: savedDeputy.mp,
          sp: savedDeputy.sp,
          czl: savedDeputy.czl,
          role_type: savedDeputy.roleType,
          is_in_warehouse: isInWarehouse,
          loyalty: savedDeputy.loyalty,
          compatibility: savedDeputy.compatibility,
          is_real: savedDeputy.is_real,
          trans_count: savedDeputy.trans_count,
          ultimate_skill_1_id: savedDeputy.ultimate_skill_1_id,
          ultimate_skill_1_level: savedDeputy.ultimate_skill_1_level,
          ultimate_skill_2_id: savedDeputy.ultimate_skill_2_id,
          ultimate_skill_2_level: savedDeputy.ultimate_skill_2_level,
        };
      }
    );
  }

  /**
   * 获取副将等级榜排名
   * 只统计未放置在仓库中的副将，也就是副将表和玩家副将表能够关联上的
   * 限制条件：只统计每一位玩家等级最高的副将
   * 使用Redis缓存，有效期1小时
   */
  async getDeputyLevelRanking(
    pageNum: number = 0,
    pageSize: number = 40
  ): Promise<{
    list: any[];
    page: number;
    sum: number;
  }> {
    try {
      // 生成缓存键
      const cacheKey = `deputy_level_ranking:${pageNum}:${pageSize}`;
      const cacheTTL = 60 * 60; // 1小时

      // 尝试从缓存获取数据
      try {
        const cachedData = await this.redisService.get(cacheKey);
        if (cachedData) {
          this.logger.log(
            `从缓存获取副将等级榜数据: pageNum=${pageNum}, pageSize=${pageSize}`
          );
          return JSON.parse(cachedData);
        }
      } catch (cacheError) {
        this.logger.warn(`读取缓存失败，将查询数据库: ${cacheError}`);
      }

      // 计算分页
      const skip = pageNum * pageSize;

      // 使用子查询获取每个玩家等级最高的副将
      const subQuery = this.deputyGeneralRepository
        .createQueryBuilder("sub_deputy")
        .select("sub_deputy.id")
        .innerJoin(
          "player_deputy",
          "sub_pd",
          "sub_pd.deputy_id = sub_deputy.id"
        )
        .where((qb) => {
          const subQuery2 = qb
            .subQuery()
            .select("MAX(sub_deputy2.lvl)")
            .from("deputy_general", "sub_deputy2")
            .innerJoin(
              "player_deputy",
              "sub_pd2",
              "sub_pd2.deputy_id = sub_deputy2.id"
            )
            .where("sub_pd2.player_id = sub_pd.player_id")
            .getQuery();
          return `sub_deputy.lvl = ${subQuery2}`;
        });

      // 主查询：获取每个玩家等级最高的副将，并按等级排序
      const queryBuilder = this.deputyGeneralRepository
        .createQueryBuilder("deputy")
        .leftJoin("deputy.base", "base")
        .innerJoin("player_deputy", "pd", "pd.deputy_id = deputy.id")
        .where(`deputy.id IN (${subQuery.getQuery()})`)
        .orderBy("deputy.lvl", "DESC") // 按等级降序排列
        .addOrderBy("deputy.id", "ASC") // 等级相同时按ID升序
        .skip(skip)
        .take(pageSize)
        .select([
          "deputy.id AS id",
          "deputy.lvl AS lvl",
          "deputy.roleType AS roleType",
          "deputy.trans_count AS trans_count",
          "base.name AS base_name",
          "pd.player_id AS owner_id",
        ]);

      // 获取总数（每个玩家等级最高的副将数量）
      const totalQuery = this.deputyGeneralRepository
        .createQueryBuilder("deputy")
        .innerJoin("player_deputy", "pd", "pd.deputy_id = deputy.id")
        .where(`deputy.id IN (${subQuery.getQuery()})`);

      const [rows, total] = await Promise.all([
        queryBuilder.getRawMany(),
        totalQuery.getCount(),
      ]);

      // 格式化返回数据
      const list = rows.map((row, index) => ({
        id: Number(row.id),
        lvl: Number(row.lvl),
        name: String(row.base_name || "未知副将"),
        num: skip + index + 1, // 排名
        roleId: Number(row.owner_id), // 归属角色ID
        roleType: this.calculateRoleType(
          Number(row.roleType),
          Number(row.trans_count)
        ), // 计算转职类型
      }));

      const result = {
        list,
        page: pageNum + 1,
        sum: total,
      };

      // 将结果存入缓存
      try {
        await this.redisService.set(cacheKey, JSON.stringify(result), cacheTTL);
        this.logger.log(
          `副将等级榜数据已缓存: pageNum=${pageNum}, pageSize=${pageSize}, TTL=${cacheTTL}秒`
        );
      } catch (cacheError) {
        this.logger.warn(`缓存副将等级榜数据失败: ${cacheError}`);
      }

      return result;
    } catch (error) {
      this.logger.error(`获取副将等级榜失败:`, error);
      throw error;
    }
  }

  /**
   * 计算转职类型
   * 根据基础职业类型和转职次数计算最终的roleType
   * 111表示3转（武士专职武士转职武士）
   * 121表示3转（武士转文人转武士）
   */
  private calculateRoleType(baseRoleType: number, transCount: number): number {
    if (transCount === 0) {
      // 未转职：1=武士, 2=文人, 3=异师
      return baseRoleType;
    } else if (transCount === 1) {
      // 1转：11=武士转武士, 12=武士转文人, 13=武士转异师, 21=文人转武士, 22=文人转文人, 23=文人转异师, 31=异师转武士, 32=异师转文人, 33=异师转异师
      return baseRoleType * 10 + baseRoleType; // 暂时简化，实际应该有转职逻辑
    } else if (transCount === 2) {
      // 2转：111=武士转武士转武士, 121=武士转文人转武士, 131=武士转异师转武士, 等等
      return baseRoleType * 100 + baseRoleType * 10 + baseRoleType; // 暂时简化
    } else if (transCount === 3) {
      // 3转：1111=武士转武士转武士转武士, 1211=武士转文人转武士转武士, 等等
      return (
        baseRoleType * 1000 +
        baseRoleType * 100 +
        baseRoleType * 10 +
        baseRoleType
      ); // 暂时简化
    } else {
      // 4转或更多
      return (
        baseRoleType * 10000 +
        baseRoleType * 1000 +
        baseRoleType * 100 +
        baseRoleType * 10 +
        baseRoleType
      ); // 暂时简化
    }
  }
}
